#pragma once

#include <string>

namespace Renderer
{
	enum class UniformType
	{
		Int,
		Float,
		FloatVector2,
		FloatVector3,
		FloatVector4,
		IntVector2,
		IntVector3,
		IntVector4,
		Bool,
		BoolVector2,
		BoolVector3,
		BoolVector4,
		FloatMatrix22,
		FloatMatrix33,
		FloatMatrix44,
		Sampler1D,
		Sampler2D,
		Sampler2DRectangle,
		Sampler2DRectangleShadow,
		Sampler3D,
		SamplerCube,
		Sampler1DShadow,
		Sampler2DShadow,
		FloatMatrix23,
		FloatMatrix24,
		FloatMatrix32,
		FloatMatrix34,
		FloatMatrix42,
		FloatMatrix43,
		Sampler1DArray,
		Sampler2DArray,
		Sampler1DArrayShadow,
		Sampler2DArrayShadow,
		SamplerCubeShadow,
		IntSampler1D,
		IntSampler2D,
		IntSampler2DRectangle,
		IntSampler3D,
		IntSamplerCube,
		IntSampler1DArray,
		IntSampler2DArray,
		UnsignedIntSampler1D,
		UnsignedIntSampler2D,
		UnsignedIntSampler2DRectangle,
		UnsignedIntSampler3D,
		UnsignedIntSamplerCube,
		UnsignedIntSampler1DArray,
		UnsignedIntSampler2DArray
	};

	class Uniform
	{
	protected:
		Uniform(std::string name, UniformType type);
	public:
		std::string GetName();

		UniformType GetDatatype();

	private:
		std::string _name;
		UniformType _type;
	};


	template<typename T>
	class TemplateUniform : public Uniform
	{
	protected:
		TemplateUniform(std::string name, UniformType type)
			:Uniform(name,type)
		{
			_name = name;
			_type = type;
		}
	public:
		std::string GetName()
		{
			return _name;
		}

		UniformType GetDatatype()
		{
			return _type;
		}

		virtual T GetValue() = 0;
		virtual void SetValue(const T& value) = 0;

	private:
		std::string _name;
		UniformType _type;
		T _value;
	};
}